﻿using Castle.MicroKernel.Registration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WJP.Dependency;
using WJP.Dependency.Installers;
using WJP.Environment;
using WJP.Events.Bus;
using WJP.Logging;

namespace WJP.ComponentModel
{
    /// <summary>
    /// 这个类为 ClientApp、ServerApp、WebApp 等类提供了一致的基类。
    /// </summary>
    public abstract class AppBase : IApp, IDisposable
    {
        /// <summary>
        /// Ioc管理器
        /// </summary>
        public IIocManager IocManager { get; }

        /// <summary>
        /// 日志记录器
        /// </summary>
        public ILogger Logger { get; private set; }

        /// <summary>
        /// 
        /// </summary>
        protected bool IsDisposed;

        /// <summary>
        /// 插件管理器
        /// </summary>
        private PluginManager PluginManager;

        public List<IPluginSource> PluginSources { get; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="optionsAction"></param>
        public AppBase(Action<AppOptions> optionsAction = null)
        {
            var options = new AppOptions();
            optionsAction?.Invoke(options);

            IocManager = options.IocManager;
            Logger = LogManager.GetLogger<AppBase>();
            PluginSources = options.PluginSources;

            if (!options.DisableAllInterceptors)
            {
                AddInterceptorRegistrars();
            }
        }

        private void AddInterceptorRegistrars()
        {
            DomainControllerInterceptorRegistrar.Initialize(IocManager);
        }

        /// <summary>
        /// 子类在合适的时间调用此方法来启动整个应用程序。
        /// <para>注意，为了支持重新启动，这个类中的所有方法都应该可以运行多次。</para>
        /// <para>但是，第二次及之后的重启，不应该使用同一个 AppImplementationBase 的实例，否则可能会造成插件重复监听同一事件。</para>
        /// </summary>
        protected void StartupApplication()
        {
            try
            {
                RegisterApp();

                InitIoc();
                InitServerStatus();

                Logger.Info("开始重置环境！");
                PrepareToStartup();
                Logger.Info("重置环境成功！");

                Logger.Info("开始初始化环境变量！");
                InitEnvironment();
                Logger.Info("初始化环境变量成功！");

                Logger.Info("开始初始化所有Plugins！");
                PluginManager.Initialize();
                OnAllPluginsIntialized();
                Logger.Info("初始化所有Plugins成功！");

                Logger.Info("开始定义模块列表！");
                OnModuleOperations();
                OnModuleOperationsCompleted();
                Logger.Info("定义模块列表成功！");

                Logger.Info("启动主过程！");
                OnMainProcessStarting();
                Logger.Info("启动主过程成功！");
                OnStartupCompleted();
                Logger.Info("整个初始化完毕！");
            }
            catch (Exception ex)
            {
                Logger.Fatal(ex.ToString(), ex);
                throw;
            }
        }

        /// <summary>
        /// 初始化服务状态信息
        /// </summary>
        protected virtual void InitServerStatus()
        {

        }

        /// <summary>
        /// 此方法中会重置整个环境。这样可以保证各插件的注册机制能再次运行
        /// <para>例如，当启动过程中出现异常时，可以重新使用 Startup 来启动应用程序开始全新的启动流程</para>
        /// </summary>
        protected virtual void PrepareToStartup()
        {
            PlatformEnvironment.Reset();
        }

        /// <summary>
        /// 初始化应用程序的环境
        /// <para>子类可在此方法中添加所需的插件、设置<see cref="WJP.PlatformEnvironment.Location"/>等</para>
        /// </summary>
        protected virtual void InitEnvironment()
        {
            // TODO:线程语言

            PlatformEnvironment.InitCustomizationPath();
        }

        #region IApp事件

        /// <summary>
        /// 所有实体元数据初始化完毕，包括实体元数据之间的关系
        /// </summary>
        public event EventHandler AllPluginsIntialized;
        /// <summary>
        /// 触发 AllPluginsIntialized 事件
        /// </summary>
        protected virtual void OnAllPluginsIntialized()
        {
            AllPluginsIntialized?.Invoke(this, EventArgs.Empty);
        }

        /// <summary>
        /// 模块定义
        /// </summary>
        public event EventHandler ModuleOperations;
        /// <summary>
        /// 模块定义
        /// </summary>
        protected virtual void OnModuleOperations()
        {
            ModuleOperations?.Invoke(this, EventArgs.Empty);
        }

        /// <summary>
        /// 模块的定义完成
        /// </summary>
        public event EventHandler ModuleOperationsCompleted;
        /// <summary>
        /// 模块的定义完成
        /// </summary>
        protected virtual void OnModuleOperationsCompleted()
        {
            ModuleOperationsCompleted?.Invoke(this, EventArgs.Empty);
        }

        /// <summary>
        /// 所有初始化工作完成
        /// </summary>
        public event EventHandler AppMetaCompleted;
        /// <summary>
        /// 触发 AppMetaCompleted 事件
        /// </summary>
        protected virtual void OnAppMetaCompiled()
        {
            AppMetaCompleted?.Invoke(this, EventArgs.Empty);
        }

        /// <summary>
        /// 主过程开始前事件
        /// </summary>
        public event EventHandler MainProcessStarting;
        /// <summary>
        /// 主过程开始前事件
        /// </summary>
        protected virtual void OnMainProcessStarting()
        {
            MainProcessStarting?.Invoke(this, EventArgs.Empty);
        }

        /// <summary>
        /// AppStartup 完毕
        /// </summary>
        public event EventHandler StartupCompleted;
        /// <summary>
        /// AppStartup 完毕
        /// </summary>
        protected virtual void OnStartupCompleted()
        {
            StartupCompleted?.Invoke(this, EventArgs.Empty);
        }

        /// <summary>
        /// 应用程序完全退出
        /// </summary>
        public event EventHandler Exit;
        /// <summary>
        /// 触发Exit事件
        /// </summary>
        protected virtual void OnExit()
        {
            Exit?.Invoke(this, EventArgs.Empty);
        }

        #endregion

        /// <summary>
        /// 
        /// </summary>
        private void InitIoc()
        {
            IocManager.IocContainer.Install(new CoreInstaller());
            PluginManager = IocManager.Resolve<PluginManager>();
            PluginManager.SetApp(this);
            foreach (var pluginSource in PluginSources)
            {
                PluginManager.AddPluginSource(pluginSource);
            }
        }

        private void ResolveLogger()
        {
            if (IocManager.IsRegistered<ILoggerFactory>())
            {
                Logger = IocManager.Resolve<ILoggerFactory>().Create(typeof(AppBase));
            }
        }

        private void RegisterApp()
        {
            if (!IocManager.IsRegistered<AppBase>())
            {
                IocManager.IocContainer.Register(
                    Component.For<AppBase>().Instance(this)
                    );
            }
        }

        public void Dispose()
        {
            if (IsDisposed)
                return;

            IsDisposed = true;

            OnExit();
        }
    }
}
